package com.onpositive.mediawiki.dataprocessors;

import java.util.HashSet;

import com.onpositive.mediawiki.propertyparser.PropertyCharacteristic;
import com.onpositive.units.ParsedProperty;
import com.onpositive.units.ParsedValue;

public abstract class AbstractDataProcessor {
	
	public static final int MIXED_PROCESSING = 1 ;
	
	private HashSet<String> inputPropertySet ;
	private HashSet<String> workingPropertySet = new HashSet<String>() ;
	private boolean mixedProcessing = false ; 
	
	public AbstractDataProcessor() {}
	
	public AbstractDataProcessor( String propertyName ) {
		
		String[] propertyNames = new String[1] ;
		propertyNames[0] = propertyName ;
		
		initNamesSet( propertyNames );
	}
	
	public AbstractDataProcessor( String[] propertyNames ) {
		
		initNamesSet( propertyNames );
	}
	
	public AbstractDataProcessor( int flags ) {
		
		mixedProcessing = ( flags & MIXED_PROCESSING ) != 0 ;
		readFlags(flags) ;
	}
	
	public AbstractDataProcessor( String propertyName, int flags ) {
		
		String[] propertyNames = new String[1] ;
		propertyNames[0] = propertyName ;
		
		initNamesSet( propertyNames );
		
		mixedProcessing = ( flags & MIXED_PROCESSING ) != 0 ;
		readFlags(flags) ;
	}
	public AbstractDataProcessor( String[] propertyNames, int flags ) {
		
		initNamesSet( propertyNames );
		
		mixedProcessing = ( flags & MIXED_PROCESSING ) != 0 ;
		readFlags(flags) ;
	}
	
	private void initNamesSet( String[] propertyNames ) {
		
		if( propertyNames != null && propertyNames.length != 0 )
		{
			this.inputPropertySet = new HashSet<String>() ;
			for( String n : propertyNames )
				if( n != null )
					this.inputPropertySet.add( n ) ;
		}
	}
	
	public final void inspect(PropertyCharacteristic pc){
		
		if( checkApplicability( pc ) )
		{
			String propertyName = pc.getCharacteristic( PropertyCharacteristic.CHAR_PROPERTY_NAME_LABEL ) ;
			if( this.inputPropertySet == null || this.inputPropertySet.contains( propertyName ) )
				this.workingPropertySet.add( propertyName ) ;			
		}
	}
	
	
	
	public final void gatherStats( ParsedProperty prop )
	{
		if( !check(prop) )
			return ;

		if( !mixedProcessing )
			doGatherPropertyStats( prop ) ;
		else
			doGatherTotalStats( prop ) ;				
	}
	
	public void applyChanges(PropertyCharacteristic pc) {
		
		if( checkApplicability( pc ) )
			doApplyChanges( pc ) ;				
	}

	public final void applyChanges( ParsedProperty prop )
	{
		if( !check(prop) )
			return ;
		
		if( !mixedProcessing )
			doApplyPropertyChange( prop ) ;
		else
			doApplayTotalChange( prop ) ;		
	}	
	
	abstract protected void readFlags( int flags ) ;

	abstract protected boolean checkApplicability(PropertyCharacteristic pc) ;
	
	abstract protected void doGatherPropertyStats( ParsedProperty prop  ) ;
	
	abstract protected void doGatherTotalStats( ParsedProperty prop  ) ;
	
	abstract protected void doApplyChanges( PropertyCharacteristic pc ) ;
	
	abstract protected void doApplyPropertyChange( ParsedProperty prop ) ;

	abstract protected void doApplayTotalChange( ParsedProperty prop ) ;

	private boolean check(ParsedProperty prop) {
		
		if( prop == null )
			return false;
		
		String propertyName = prop.getName() ;
		Iterable<ParsedValue> values = prop.getValues() ;
		
		if( propertyName == null || propertyName.length() == 0 
								 || !this.workingPropertySet.contains( propertyName )
								 || values == null
								 || !values.iterator().hasNext() )
			return false;	
		
		boolean gotNonNullValue = false ; 
		for( ParsedValue pVal : values )
			gotNonNullValue = ( gotNonNullValue || (pVal.value()!=null) ) ;

		return gotNonNullValue ;
	}

	
}
